package internal

import (
	"encoding/binary"
	"errors"
	"hash/crc32"
	"time"
)

type Entry struct {
	crc       uint32 // 校验值
	Timestamp int64
	KeySize   uint32
	ValueSize uint32
	Key       []byte
	Value     []byte
}

// 可以不用管 crc
func (e *Entry) Encode() []byte {
	timestamp := time.Now().Unix()
	data := make([]byte, 4+8+4+4)
	binary.BigEndian.PutUint64(data[4:12], uint64(timestamp))
	binary.BigEndian.PutUint32(data[12:16], e.KeySize)
	binary.BigEndian.PutUint32(data[16:20], e.ValueSize)
	data = append(data, e.Key...)
	data = append(data, e.Value...)
	crc := crc32.ChecksumIEEE(data[4:])
	binary.BigEndian.PutUint32(data[0:4], crc)
	return data
}

func (e *Entry) Decode(data []byte) error {
	if len(data) < 20 {
		return errors.New("data is not valid")
	}
	pcrc := binary.BigEndian.Uint32(data[0:4])
	crc := crc32.ChecksumIEEE(data[4:])
	if pcrc != crc {
		return errors.New("crc failed, data is not valid")
	}
	e.Timestamp = int64(binary.BigEndian.Uint64(data[4:12]))
	e.KeySize = binary.BigEndian.Uint32(data[12:16])
	e.ValueSize = binary.BigEndian.Uint32(data[16:20])
	keyPos := 20 + e.KeySize
	e.Key = data[20:keyPos]
	e.Value = data[keyPos : keyPos+e.ValueSize]
	return nil
}

func (e *Entry) DecodeHeader(header []byte) error {
	if len(header) < 20 {
		return errors.New("header is not valid")
	}
	e.crc = binary.BigEndian.Uint32(header[0:4])
	e.Timestamp = int64(binary.BigEndian.Uint64(header[4:12]))
	e.KeySize = binary.BigEndian.Uint32(header[12:16])
	e.ValueSize = binary.BigEndian.Uint32(header[16:20])
	return nil
}

func (e *Entry) SetKV(header, key, val []byte) error {
	cdata := append(header, key...)
	cdata = append(cdata, val...)
	crc := crc32.ChecksumIEEE(cdata[4:])
	if e.crc != crc {
		return errors.New("crc failed, data is not valid")
	}
	e.Key = key
	e.Value = val
	return nil
}
